function result = ActiveModelSelection( dataSet, candidates, budget, preLabels, strategy, criteria)
%FUNCTION `ActiveModelSelection` return the better model within the
%candidates
%   @return         {model, correct, kfcvCorrect }
%   @dataSet        the dataSet to run
%   @candidates     cells, record names of the models to be evaluated,
%       e.g. {'TSVM','GSSL'}
%       models should be in the form of XXX(x, y, l_ind)
%       we use default parameters now
    load(['data/',dataSet,'.mat']);
    
    lIndex = cell(budget+1);
    models = cell(budget+1, length(candidates)); % element is {model, kfcv, acc}
    records = cell(budget+1); % cell, elements are cells
    
    % Initialize the labels
    temp = randperm(numel(y));
    lIndex{1} = temp(1:preLabels);
    
    % train M^(1)
    for j = 1:length(candidates)
        mo = str2func(candidates{j});
        models{1,j} = mo(x, y, lIndex{1});
    end
    
    % compute Weighted Euclidean distance
    if strategy == 1
        stdA = std(x);
        records{1} = squareform(pdist(x, 'seuclidean', stdA));
    end
    
    for i=1:budget
        tic;
        fprintf('The %d iteration:',i);
        [lIndex{i+1}, records{i+1}] = selectingStrategy(x, y, lIndex, records, models, i, strategy);
%         for j=1:length(candidates)
%             mo = str2func(candidates{j});
%             models{i+1,j} = mo(x, y, lIndex{i});
%         end
        fprintf('time:%g\n', toc);
    end
    for j=1:length(candidates)
        mo = str2func(candidates{j});
        models{budget+1,j} = mo(x, y, lIndex{budget+1});
    end
    result = selectingCriteria(candidates, models, records, criteria);
end

function [lIndex,record] = selectingStrategy(x, y, l_ind, records, models, i, type)
%FUNCTION `selectingStrategy` call certain strategy to select an unlabel 
%         data and add label to it
%           Strategy should be like XXX(x, y, l_ind, recods, models, i)
%   @return     lIndex: new label indexs
%   @reutrn     record: records of computing result, maybe used later
%   @x
%   @y
%   @l_ind
%   @models
%   @i
%   @type       the strategy type
    switch(type)
        case 1
            [lIndex, record] = randomStrategy(x, y, l_ind, records, models, i);
        case 2
            [lIndex, record] = nnStrategy(x, y, l_ind, records, models, i);
        otherwise
            fprintf('STRATEGY MISSING!\n');
    end
end


function result = selectingCriteria(candidates, models, records, type)
%FUNCTION `selectingCriteria` use the records to select the better model
%           base on the criteria
%       @return     the selected model
%       @candidates
%       @models     the trained models in the iterations
%       @records    the results in the iterations
%       @type       criteria type
    B = size(models, 1);
    accs = zeros(length(candidates), 1);
    tAccs = zeros(length(candidates), 1);
    kfcvacc = zeros(length(candidates), 1);
    for ind = 1:length(candidates)
        %models{B, ind}
        accs(ind) = models{B, ind}.kfcv.acc; 
        tAccs(ind) = models{1, ind}.acc;
        kfcvacc(ind) = models{1, ind}.kfcv.acc;
    end
    [~, maxIndex] = max(accs);
    [~, maxIndex2] = max(tAccs);
    [~, maxIndex3] = max(kfcvacc);
    result.correct = (maxIndex==maxIndex2);
    result.model = candidates{maxIndex};
    result.kfcvCorrect = (maxIndex3 == maxIndex2);
end
